# -*- coding: utf-8 -*-

# This code is part of Amoco
# Copyright (C) 2014 Axel Tillequin (bdcht3@gmail.com)
# published under GPLv2 license

# spec_xxx files are providers for instruction objects.

from .utils import *

# ------------------------------------------------------
# amoco x86 FPU (x87) instruction specs:
# ------------------------------------------------------

ISPECS = []


@ispec_ia32("16>[ {0f}{77} ]", mnemonic="EMMS", type=type_cpu_state)
def ia32_nooperand(obj):
    pass


@ispec_ia32("16>[ {d9} reg(3) 0 0011 ]", mnemonic="FLD")  # D9 C0+i
@ispec_ia32("16>[ {d9} reg(3) 1 0011 ]", mnemonic="FXCH")  # D9 C8+i
@ispec_ia32("16>[ {d8} reg(3) 0 1011 ]", mnemonic="FCOM")  # D8 D0+i
@ispec_ia32("16>[ {d8} reg(3) 1 1011 ]", mnemonic="FCOMP")  # D8 D8+i
@ispec_ia32("16>[ {dd} reg(3) 0 0011 ]", mnemonic="FFREE")  # DD C0+i
@ispec_ia32("16>[ {df} reg(3) 0 0011 ]", mnemonic="FFREEP")  # DF C0+i
@ispec_ia32("16>[ {dd} reg(3) 0 1011 ]", mnemonic="FST")  # DD D0+i
@ispec_ia32("16>[ {dd} reg(3) 1 1011 ]", mnemonic="FSTP")  # DD D8+i
@ispec_ia32("16>[ {dd} reg(3) 0 0111 ]", mnemonic="FUCOM")  # DD E0+i
@ispec_ia32("16>[ {dd} reg(3) 1 0111 ]", mnemonic="FUCOMP")  # DD E8+i
def ia32_fpu_reg(obj, reg):
    obj.operands = [env.st(reg)]
    obj.type = type_data_processing


@ispec_ia32("*>[ {d8} /0 ]", mnemonic="FADD", _size=32)
@ispec_ia32("*>[ {d8} /1 ]", mnemonic="FMUL", _size=32)
@ispec_ia32("*>[ {d8} /2 ]", mnemonic="FCOM", _size=32)
@ispec_ia32("*>[ {d8} /3 ]", mnemonic="FCOMP", _size=32)
@ispec_ia32("*>[ {d8} /4 ]", mnemonic="FSUB", _size=32)
@ispec_ia32("*>[ {d8} /5 ]", mnemonic="FSUBR", _size=32)
@ispec_ia32("*>[ {d8} /6 ]", mnemonic="FDIV", _size=32)
@ispec_ia32("*>[ {d8} /7 ]", mnemonic="FDIVR", _size=32)
@ispec_ia32("*>[ {d9} /0 ]", mnemonic="FLD", _size=32)
@ispec_ia32("*>[ {d9} /2 ]", mnemonic="FST", _size=32)
@ispec_ia32("*>[ {d9} /3 ]", mnemonic="FSTP", _size=32)
@ispec_ia32("*>[ {d9} /4 ]", mnemonic="FLDENV", _size=28 * 8)  # TODO : 16 bits size
@ispec_ia32("*>[ {d9} /5 ]", mnemonic="FLDCW", _size=16)
@ispec_ia32("*>[ {d9} /6 ]", mnemonic="FNSTENV", _size=28 * 8)
@ispec_ia32("*>[ {d9} /7 ]", mnemonic="FNSTCW", _size=16)
@ispec_ia32("*>[ {da} /0 ]", mnemonic="FIADD", _size=32)
@ispec_ia32("*>[ {da} /1 ]", mnemonic="FIMUL", _size=32)
@ispec_ia32("*>[ {da} /2 ]", mnemonic="FICOM", _size=32)
@ispec_ia32("*>[ {da} /3 ]", mnemonic="FICOMP", _size=32)
@ispec_ia32("*>[ {da} /4 ]", mnemonic="FISUB", _size=32)
@ispec_ia32("*>[ {da} /5 ]", mnemonic="FISUBR", _size=32)
@ispec_ia32("*>[ {da} /6 ]", mnemonic="FIDIV", _size=32)
@ispec_ia32("*>[ {da} /7 ]", mnemonic="FIDIVR", _size=32)
@ispec_ia32("*>[ {db} /0 ]", mnemonic="FILD", _size=32)
@ispec_ia32("*>[ {db} /1 ]", mnemonic="FISTTP", _size=32)
@ispec_ia32("*>[ {db} /2 ]", mnemonic="FIST", _size=32)
@ispec_ia32("*>[ {db} /3 ]", mnemonic="FISTP", _size=32)
@ispec_ia32("*>[ {db} /5 ]", mnemonic="FLD", _size=80)
@ispec_ia32("*>[ {db} /7 ]", mnemonic="FSTP", _size=80)
@ispec_ia32("*>[ {dc} /0 ]", mnemonic="FADD", _size=64)
@ispec_ia32("*>[ {dc} /1 ]", mnemonic="FMUL", _size=64)
@ispec_ia32("*>[ {dc} /2 ]", mnemonic="FCOM", _size=64)
@ispec_ia32("*>[ {dc} /3 ]", mnemonic="FCOMP", _size=64)
@ispec_ia32("*>[ {dc} /4 ]", mnemonic="FSUB", _size=64)
@ispec_ia32("*>[ {dc} /5 ]", mnemonic="FSUBR", _size=64)
@ispec_ia32("*>[ {dc} /6 ]", mnemonic="FDIV", _size=64)
@ispec_ia32("*>[ {dc} /7 ]", mnemonic="FDIVR", _size=64)
@ispec_ia32("*>[ {dd} /0 ]", mnemonic="FLD", _size=64)
@ispec_ia32("*>[ {dd} /1 ]", mnemonic="FISTTP", _size=64)
@ispec_ia32("*>[ {dd} /2 ]", mnemonic="FST", _size=64)
@ispec_ia32("*>[ {dd} /3 ]", mnemonic="FSTP", _size=64)
@ispec_ia32("*>[ {dd} /4 ]", mnemonic="FRSTOR", _size=108 * 8)  # TODO : 16 bits size
@ispec_ia32("*>[ {dd} /6 ]", mnemonic="FNSAVE", _size=108 * 8)  # TODO : 16 bits size
@ispec_ia32("*>[ {de} /0 ]", mnemonic="FIADD", _size=16)
@ispec_ia32("*>[ {de} /1 ]", mnemonic="FIMUL", _size=16)
@ispec_ia32("*>[ {de} /2 ]", mnemonic="FICOM", _size=16)
@ispec_ia32("*>[ {de} /3 ]", mnemonic="FICOMP", _size=16)
@ispec_ia32("*>[ {de} /4 ]", mnemonic="FISUB", _size=16)
@ispec_ia32("*>[ {de} /5 ]", mnemonic="FISUBR", _size=16)
@ispec_ia32("*>[ {de} /6 ]", mnemonic="FIDIV", _size=16)
@ispec_ia32("*>[ {de} /7 ]", mnemonic="FIDIVR", _size=16)
@ispec_ia32("*>[ {df} /0 ]", mnemonic="FILD", _size=16)
@ispec_ia32("*>[ {df} /1 ]", mnemonic="FISTTP", _size=16)
@ispec_ia32("*>[ {df} /2 ]", mnemonic="FIST", _size=16)
@ispec_ia32("*>[ {df} /3 ]", mnemonic="FISTP", _size=16)
@ispec_ia32("*>[ {df} /4 ]", mnemonic="FBLD", _size=80)
@ispec_ia32("*>[ {df} /5 ]", mnemonic="FILD", _size=64)
@ispec_ia32("*>[ {df} /6 ]", mnemonic="FBSTP", _size=80)
@ispec_ia32("*>[ {df} /7 ]", mnemonic="FISTP", _size=64)
@ispec_ia32("*>[ {9b}{d9} /7 ]", mnemonic="FSTCW", _size=16)
@ispec_ia32("*>[ {9b}{d9} /6 ]", mnemonic="FSTENV", _size=28 * 8)
@ispec_ia32("*>[ {9b}{dd} /6 ]", mnemonic="FSAVE", _size=108 * 8)  # TODO : 16 bits size
@ispec_ia32("*>[ {0f}{ae} /0 ]", mnemonic="FXSAVE", _size=512 * 8)
@ispec_ia32("*>[ {0f}{ae} /1 ]", mnemonic="FXRSTOR", _size=512 * 8)
def ia32_fpu_mem(obj, Mod, RM, data, _size):
    op1, data = getModRM(obj, Mod, RM, data)
    if op1._is_reg:
        raise InstructionError(obj)
    op1.size = _size
    obj.operands = [op1]
    obj.type = type_data_processing


@ispec_ia32("24>[ {9b}{df}{e0} ]", mnemonic="FSTSW")
@ispec_ia32("16>[     {df}{e0} ]", mnemonic="FNSTSW")
def ia32_fstsw_ax(obj):
    obj.operands = [env.getreg(0, 16)]
    obj.type = type_data_processing


@ispec_ia32("*>[ {9b}{dd} /7 ]", mnemonic="FSTSW")
@ispec_ia32("*>[     {dd} /7 ]", mnemonic="FNSTSW")
def ia32_fstsw(obj, Mod, RM, data):
    op1, data = getModRM(obj, Mod, RM, data)
    obj.operands = [op1]
    obj.type = type_data_processing


@ispec_ia32("16>[ {d9}{d0} ]", mnemonic="FNOP")
@ispec_ia32("16>[ {d9}{e0} ]", mnemonic="FCHS")
@ispec_ia32("16>[ {d9}{e1} ]", mnemonic="FABS")
@ispec_ia32("16>[ {d9}{e4} ]", mnemonic="FTST")
@ispec_ia32("16>[ {d9}{e5} ]", mnemonic="FXAM")
@ispec_ia32("16>[ {d9}{e8} ]", mnemonic="FLD1")
@ispec_ia32("16>[ {d9}{e9} ]", mnemonic="FLDL2T")
@ispec_ia32("16>[ {d9}{ea} ]", mnemonic="FLDL2E")
@ispec_ia32("16>[ {d9}{eb} ]", mnemonic="FLDPI")
@ispec_ia32("16>[ {d9}{ec} ]", mnemonic="FLDLG2")
@ispec_ia32("16>[ {d9}{ed} ]", mnemonic="FLDLN2")
@ispec_ia32("16>[ {d9}{ee} ]", mnemonic="FLDZ")
@ispec_ia32("16>[ {d9}{f0} ]", mnemonic="F2XM1")
@ispec_ia32("16>[ {d9}{f1} ]", mnemonic="FYL2X")
@ispec_ia32("16>[ {d9}{f2} ]", mnemonic="FPTAN")
@ispec_ia32("16>[ {d9}{f3} ]", mnemonic="FPATAN")
@ispec_ia32("16>[ {d9}{f4} ]", mnemonic="FXTRACT")
@ispec_ia32("16>[ {d9}{f5} ]", mnemonic="FPREM1")
@ispec_ia32("16>[ {d9}{f6} ]", mnemonic="FDECSTP")
@ispec_ia32("16>[ {d9}{f7} ]", mnemonic="FINCSTP")
@ispec_ia32("16>[ {d9}{f8} ]", mnemonic="FPREM")
@ispec_ia32("16>[ {d9}{f9} ]", mnemonic="FYL2XP1")
@ispec_ia32("16>[ {d9}{fa} ]", mnemonic="FSQRT")
@ispec_ia32("16>[ {d9}{fb} ]", mnemonic="FSINCOS")
@ispec_ia32("16>[ {d9}{fc} ]", mnemonic="FRNDINT")
@ispec_ia32("16>[ {d9}{fd} ]", mnemonic="FSCALE")
@ispec_ia32("16>[ {d9}{fe} ]", mnemonic="FSIN")
@ispec_ia32("16>[ {d9}{ff} ]", mnemonic="FCOS")
@ispec_ia32("16>[ {da}{e9} ]", mnemonic="FUCOMPP")
@ispec_ia32("16>[ {db}{e2} ]", mnemonic="FNCLEX")
@ispec_ia32("16>[ {db}{e3} ]", mnemonic="FNINIT")
@ispec_ia32("16>[ {de}{d9} ]", mnemonic="FCOMPP")
@ispec_ia32("24>[ {9b}{db}{e2} ]", mnemonic="FCLEX")
@ispec_ia32("24>[ {9b}{db}{e3} ]", mnemonic="FINIT")
def fld_fpu_noop(obj):
    obj.type = type_data_processing


@ispec_ia32("16>[ {d8} reg(3) 0 0111 ]", mnemonic="FSUB", _src=None, _dest=0)  # D8 E0+i
@ispec_ia32("16>[ {dc} reg(3) 1 0111 ]", mnemonic="FSUB", _src=0, _dest=None)  # DC E8+i
@ispec_ia32(
    "16>[ {de} reg(3) 1 0111 ]", mnemonic="FSUBP", _src=0, _dest=None
)  # DE E8+i
@ispec_ia32(
    "16>[ {d8} reg(3) 1 0111 ]", mnemonic="FSUBR", _src=None, _dest=0
)  # D8 E8+i
@ispec_ia32(
    "16>[ {dc} reg(3) 0 0111 ]", mnemonic="FSUBR", _src=0, _dest=None
)  # DC E0+i
@ispec_ia32(
    "16>[ {de} reg(3) 0 0111 ]", mnemonic="FSUBRP", _src=0, _dest=None
)  # DE E0+i
@ispec_ia32("16>[ {d8} reg(3) 0 0011 ]", mnemonic="FADD", _src=None, _dest=0)  # D8 C0+i
@ispec_ia32("16>[ {dc} reg(3) 0 0011 ]", mnemonic="FADD", _src=0, _dest=None)  # DC C0+i
@ispec_ia32(
    "16>[ {de} reg(3) 0 0011 ]", mnemonic="FADDP", _src=0, _dest=None
)  # DE C0+i
@ispec_ia32("16>[ {d8} reg(3) 0 1111 ]", mnemonic="FDIV", _src=None, _dest=0)  # D8 F0+i
@ispec_ia32("16>[ {dc} reg(3) 1 1111 ]", mnemonic="FDIV", _src=0, _dest=None)  # DC F8+i
@ispec_ia32(
    "16>[ {de} reg(3) 1 1111 ]", mnemonic="FDIVP", _src=0, _dest=None
)  # DE F8+i
@ispec_ia32(
    "16>[ {d8} reg(3) 1 1111 ]", mnemonic="FDIVR", _src=None, _dest=0
)  # D8 F8+i
@ispec_ia32(
    "16>[ {dc} reg(3) 0 1111 ]", mnemonic="FDIVR", _src=0, _dest=None
)  # DC F0+i
@ispec_ia32(
    "16>[ {de} reg(3) 0 1111 ]", mnemonic="FDIVRP", _src=0, _dest=None
)  # DE F0+i
@ispec_ia32("16>[ {d8} reg(3) 1 0011 ]", mnemonic="FMUL", _src=None, _dest=0)  # D8 C8+i
@ispec_ia32("16>[ {dc} reg(3) 1 0011 ]", mnemonic="FMUL", _src=0, _dest=None)  # DC C8+i
@ispec_ia32(
    "16>[ {de} reg(3) 1 0011 ]", mnemonic="FMULP", _src=0, _dest=None
)  # DE C8+i
@ispec_ia32(
    "16>[ {da} reg(3) 0 0011 ]", mnemonic="FCMOVB", _src=None, _dest=0
)  # DA C0+i
@ispec_ia32(
    "16>[ {da} reg(3) 1 0011 ]", mnemonic="FCMOVE", _src=None, _dest=0
)  # DA C8+i
@ispec_ia32(
    "16>[ {da} reg(3) 0 1011 ]", mnemonic="FCMOVBE", _src=None, _dest=0
)  # DA D0+i
@ispec_ia32(
    "16>[ {da} reg(3) 1 1011 ]", mnemonic="FCMOVU", _src=None, _dest=0
)  # DA D8+i
@ispec_ia32(
    "16>[ {db} reg(3) 0 0011 ]", mnemonic="FCMOVNB", _src=None, _dest=0
)  # DB C0+i
@ispec_ia32(
    "16>[ {db} reg(3) 1 0011 ]", mnemonic="FCMOVNE", _src=None, _dest=0
)  # DB C8+i
@ispec_ia32(
    "16>[ {db} reg(3) 0 1011 ]", mnemonic="FCMOVNBE", _src=None, _dest=0
)  # DB D0+i
@ispec_ia32(
    "16>[ {db} reg(3) 1 1011 ]", mnemonic="FCMOVNU", _src=None, _dest=0
)  # DB D8+i
@ispec_ia32(
    "16>[ {db} reg(3) 0 1111 ]", mnemonic="FCOMI", _src=None, _dest=0
)  # DB F0+i
@ispec_ia32(
    "16>[ {df} reg(3) 0 1111 ]", mnemonic="FCOMIP", _src=None, _dest=0
)  # DF F0+i
@ispec_ia32(
    "16>[ {db} reg(3) 1 0111 ]", mnemonic="FUCOMI", _src=None, _dest=0
)  # DB E8+i
@ispec_ia32(
    "16>[ {df} reg(3) 1 0111 ]", mnemonic="FUCOMIP", _src=None, _dest=0
)  # DF E8+i
def ia32_fpu_st(obj, reg, _dest, _src):
    # FSUBP
    if _dest is None and _src is None:
        return
    if _dest is None:
        _dest = reg
    elif _src is None:
        _src = reg
    op1 = env.st(_dest)
    op2 = env.st(_src)
    obj.operands = [op1, op2]
    obj.type = type_data_processing
